package com.jse;

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.Base64;

import javax.imageio.ImageIO;
import javax.sound.sampled.LineUnavailableException;

/**
 * 提供了一系列用于操作 AWT 和 Swing 库的方法。
 * 这些方法可以帮助执行各种与图形用户界面相关的任务，
 * 如屏幕捕获、图像处理、文件操作等。
 */
public class Awts {

    private static Robot robot;
    
    /**
     * 获取或创建一个 Robot 对象。
     * @return Robot 对象。
     */
    public static Robot robot() {
        if (robot == null) {
            try {
                robot = new Robot();
            } catch (AWTException e) {
                e.printStackTrace();
            }
        }
        return robot;
    }

    /**
     * 获取系统的剪贴板。
     * @return 系统剪贴板对象。
     */
    public static Clipboard clipboard() {
        return Toolkit.getDefaultToolkit().getSystemClipboard();
    }

    /**
     * 获取默认的 Toolkit 实例。
     * @return 默认的 Toolkit 实例。
     */
    public static Toolkit tookit() {
        return Toolkit.getDefaultToolkit();
    }

    /**
     * 获取默认的 Desktop 实例。
     * @return 默认的 Desktop 实例。
     */
    public static Desktop desktop() {
        return Desktop.getDesktop();
    }

    /**
     * 打开网页浏览器并导航到指定的 URI。
     * @param uri 要打开的 URI。
     * @throws IOException 如果无法打开浏览器。
     */
    public static void browser(URI uri) throws IOException {
        desktop().browse(uri);
    }

    /**
     * 设置或取消设置突然终止应用程序的能力。
     * @param enable 如果为 true，则启用突然终止；否则禁用。
     * @throws IOException 如果无法设置。
     */
    public static void termination(boolean enable) throws IOException {
        if (enable) {
            desktop().enableSuddenTermination();
        } else {
            desktop().disableSuddenTermination();
        }
    }

    /**
     * 使用默认编辑器打开指定的文件。
     * @param file 要编辑的文件路径。
     * @throws IOException 如果无法打开文件。
     */
    public static void edit(String file) throws IOException {
        desktop().edit(new File(file));
    }

    /**
     * 使用默认程序打开指定的文件。
     * @param file 要打开的文件路径。
     * @throws IOException 如果无法打开文件。
     */
    public static void open(String file) throws IOException {
        desktop().open(new File(file));
    }

    /**
     * 打印指定的文件。
     * @param file 要打印的文件路径。
     * @throws IOException 如果无法打印文件。
     */
    public static void print(String file) throws IOException {
        desktop().print(new File(file));
    }

    /**
     * 使用默认邮件客户端发送邮件。
     * @param uri 包含邮件信息的 URI。
     * @throws IOException 如果无法发送邮件。
     */
    public static void mail(String uri) throws IOException {
        desktop().mail(URI.create(uri));
    }

    /**
     * 将指定的文件移动到回收站。
     * @param file 要移动到回收站的文件路径。
     * @throws IOException 如果无法移动文件。
     */
    public static void recycle(String file) throws IOException {
        desktop().moveToTrash(new File(file));
    }

    /**
     * 生成一个随机颜色。
     * @return 随机颜色对象。
     */
    public static Color randomColor() {
        return new Color(Lang.rand(255), Lang.rand(255), Lang.rand(255));
    }

    /**
     * 生成一个指定范围内的随机颜色。
     * @param begin 范围开始值。
     * @param end 范围结束值。
     * @return 随机颜色对象。
     */
    public static Color randomColor(int begin, int end) {
        return new Color(Lang.rand(begin, end), Lang.rand(begin, end), Lang.rand(begin, end));
    }

    /**
     * 将颜色转换为 RGB 字符串格式。
     * @param color 颜色对象。
     * @return RGB 字符串格式。
     */
    public static String rgb(Color color) {
        return "rgb(%d, %d, %d)".formatted(color.getRed(), color.getGreen(), color.getBlue());
    }

    /**
     * 根据字符串解析颜色。
     * @param colorStr 颜色字符串。
     * @return 解析后的颜色对象。
     */
    public static Color color(String colorStr) {
        if (colorStr.charAt(0) == '#') {
            return Color.decode(colorStr);
        } else if (colorStr.indexOf(",") != -1) {
            var rgb = colorStr.split(",");
            return new Color(Integer.valueOf(rgb[0]), Integer.valueOf(rgb[1]), Integer.valueOf(rgb[2]));
        }
        return Color.getColor(colorStr);
    }

    /**
     * 创建一个字体对象。
     * @param fontFile 字体文件。
     * @return 字体对象。
     */
    public static Font font(File fontFile) {
        try {
            return Font.createFont(Font.TRUETYPE_FONT, fontFile);
        } catch (FontFormatException e) {
            try {
                return Font.createFont(Font.TYPE1_FONT, fontFile);
            } catch (Exception e1) {
                throw new RuntimeException(e);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 生成验证码图片。
     * @param code 验证码文本。
     * @param out 输出流。
     * @throws IOException 如果写入图片时发生错误。
     */
    public static void captcha(String code, OutputStream out) throws IOException {
        int width = code.length() * 30, height = 45;
        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        var g = img.createGraphics();
        g.setBackground(Color.WHITE);
        g.fillRect(0, 0, img.getWidth(), img.getHeight());
        for (int i = 0; i < 50; i++) {
            g.setColor(randomColor());
            g.drawOval(Lang.rand(width), Lang.rand(height), Lang.rand(height >> 1), Lang.rand(height >> 1));
        }
        g.setFont(new Font(Font.DIALOG, Font.PLAIN, 45));
        g.drawString(code, 10, 40);
        g.dispose();
        ImageIO.write(img, "jpg", out);
    }

    /**
     * 为图片添加水印。
     * @param source 图片文件路径。
     * @param text 要添加的文字。
     * @param color 水印颜色。
     * @param fontSize 文字大小。
     * @param x 文字位置 X 坐标。
     * @param y 文字位置 Y 坐标。
     * @throws IOException 如果读取或写入文件时发生错误。
     */
    public static void watermark(String source, String text, String color, int fontSize, int x, int y) throws IOException {
        final BufferedImage targetImg = ImageIO.read(new File(source));
        int width = targetImg.getWidth();
        int height = targetImg.getHeight();
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
        var g = bufferedImage.createGraphics();
        g.drawImage(targetImg, 0, 0, width, height, null);
        g.setColor(Color.getColor(color));
        g.setFont(new Font("微软雅黑", Font.ITALIC, fontSize));
        g.drawString(text, x, y);
        g.dispose();
        FileOutputStream outImgStream = new FileOutputStream(source + ".jpg");
        ImageIO.write(bufferedImage, "jpg", outImgStream);
        outImgStream.flush();
        outImgStream.close();
    }

    /**
     * 缩放图片。
     * @param source 图片文件路径。
     * @param width 新宽度。
     * @param height 新高度。
     * @throws IOException 如果读取或写入文件时发生错误。
     */
    public static void scale(String source, int width, int height) throws IOException {
        final BufferedImage originalImage = ImageIO.read(new File(source));
        Image resultingImage = originalImage.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING);
        BufferedImage outputImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        outputImage.getGraphics().drawImage(resultingImage, 0, 0, null);
        ImageIO.write(outputImage, "jpg", new FileOutputStream(source));
    }

    /**
     * 缩放图片。
     * @param source 图片文件路径。
     * @param percentage 缩放比例。
     * @throws IOException 如果读取或写入文件时发生错误。
     */
    public static void scale(String source, double percentage) throws IOException {
        final BufferedImage originalImage = ImageIO.read(new File(source));
        int width = (int) (originalImage.getWidth() * percentage);
        int height = (int) (originalImage.getHeight() * percentage);
        Image resultingImage = originalImage.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING);
        BufferedImage outputImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        outputImage.getGraphics().drawImage(resultingImage, 0, 0, null);
        ImageIO.write(outputImage, "jpg", new FileOutputStream(source));
    }

    /**
     * 截取屏幕截图。
     * @param out 输出文件路径。
     * @throws AWTException 如果无法创建 Robot 对象。
     * @throws IOException 如果写入文件时发生错误。
     */
    public static void screen(String out) throws AWTException, IOException {
        Dimension d = tookit().getScreenSize();
        Rectangle screenRect = new Rectangle(d);
        BufferedImage bufferedImage = robot().createScreenCapture(screenRect);
        ImageIO.write(bufferedImage, "png", new File(out));
    }

    /**
     * 生成并写入一个包含特定频率的正弦波信号到输出流。
     * @param frequencyOfSignal 信号的频率。
     * @param seconds 信号的持续时间（秒）。
     * @return 生成的正弦波信号。
     */
    public static byte[] generateSineWavefreq(int frequencyOfSignal, int seconds) {
        byte[] sin = new byte[seconds * 8000];
        double samplingInterval = (double) (8000 / frequencyOfSignal);
        for (int i = 0; i < sin.length; i++) {
            double angle = (2.0 * Math.PI * i) / samplingInterval;
            sin[i] = (byte) (Math.sin(angle) * 127);
        }
        return sin;
    }

    /**
     * 将输入流中的图像转换为 Base64 编码的字符串。
     * @param in 输入流。
     * @param type 图像类型（例如 "jpg" 或 "png"）。
     * @return 图像的 Base64 编码字符串。
     */
    public static String base64(InputStream in, String type) {
        try (in) {
            BufferedImage img = ImageIO.read(in);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ImageIO.write(img, type, ImageIO.createImageOutputStream(out));
            return Base64.getEncoder().encodeToString(out.toByteArray()).replace(" ", "+");
        } catch (Exception e) {
            throw new RuntimeException("obj:{} is not support case to type:{} base64!");
        }
    }
    
    public static void main(String[] args) throws IOException, AWTException, LineUnavailableException {
//		ShortMessage m=new ShortMessage();
////		MidiDevice.Info info=
//		javax.sound.midi.Synthesizer s;
//		ServiceLoader<MidiDeviceProvider> mps=ServiceLoader.load(MidiDeviceProvider.class);
//		MidiDeviceProvider mp=mps.findFirst().get();
//		System.out.println(Arrays.toString(mp.getDeviceInfo()));
//		final AudioFormat af = new AudioFormat(8000, 16, 1, true, true);
//		SourceDataLine line = AudioSystem.getSourceDataLine(af);
//		line.open(af);
//        line.start();
//		byte[] bs=generateSineWavefreq(1000,2);
//		line.write(bs, 0, bs.length);
//		line.drain();
//		
//		AudioInputStream ais=new AudioInputStream(new ByteArrayInputStream(bs),af,bs.length
//				);
//		AudioSystem.write(ais, Type.WAVE, new File("d:/1.wav"));
		Awts.captcha("8887",new FileOutputStream("d:/1.png"));
	}
}